@@ -220,6 +220,131 @@ def test_negative_locations_for_compile(self):
220
220
# This also must not crash:
221
221
ast .parse (tree , optimize = 2 )
222
222
223
+ def test_docstring_optimization_single_node (self ):
224
+ # https://github.com/python/cpython/issues/137308
225
+ class_example1 = textwrap .dedent ('''
226
+ class A:
227
+ """Docstring"""
228
+ ''' )
229
+ class_example2 = textwrap .dedent ('''
230
+ class A:
231
+ """
232
+ Docstring"""
233
+ ''' )
234
+ def_example1 = textwrap .dedent ('''
235
+ def some():
236
+ """Docstring"""
237
+ ''' )
238
+ def_example2 = textwrap .dedent ('''
239
+ def some():
240
+ """Docstring
241
+ """
242
+ ''' )
243
+ async_def_example1 = textwrap .dedent ('''
244
+ async def some():
245
+ """Docstring"""
246
+ ''' )
247
+ async_def_example2 = textwrap .dedent ('''
248
+ async def some():
249
+ """
250
+ Docstring
251
+ """
252
+ ''' )
253
+ for code in [
254
+ class_example1 ,
255
+ class_example2 ,
256
+ def_example1 ,
257
+ def_example2 ,
258
+ async_def_example1 ,
259
+ async_def_example2 ,
260
+ ]:
261
+ for opt_level in [0 , 1 , 2 ]:
262
+ with self .subTest (code = code , opt_level = opt_level ):
263
+ mod = ast .parse (code , optimize = opt_level )
264
+ self .assertEqual (len (mod .body [0 ].body ), 1 )
265
+ if opt_level == 2 :
266
+ pass_stmt = mod .body [0 ].body [0 ]
267
+ self .assertIsInstance (pass_stmt , ast .Pass )
268
+ self .assertEqual (
269
+ vars (pass_stmt ),
270
+ {
271
+ 'lineno' : 3 ,
272
+ 'col_offset' : 4 ,
273
+ 'end_lineno' : 3 ,
274
+ 'end_col_offset' : 8 ,
275
+ },
276
+ )
277
+ else :
278
+ self .assertIsInstance (mod .body [0 ].body [0 ], ast .Expr )
279
+ self .assertIsInstance (
280
+ mod .body [0 ].body [0 ].value ,
281
+ ast .Constant ,
282
+ )
283
+
284
+ compile (code , "a" , "exec" )
285
+ compile (code , "a" , "exec" , optimize = opt_level )
286
+ compile (mod , "a" , "exec" )
287
+ compile (mod , "a" , "exec" , optimize = opt_level )
288
+
289
+ def test_docstring_optimization_multiple_nodes (self ):
290
+ # https://github.com/python/cpython/issues/137308
291
+ class_example = textwrap .dedent (
292
+ """
293
+ class A:
294
+ '''
295
+ Docstring
296
+ '''
297
+ x = 1
298
+ """
299
+ )
300
+
301
+ def_example = textwrap .dedent (
302
+ """
303
+ def some():
304
+ '''
305
+ Docstring
306
+
307
+ '''
308
+ x = 1
309
+ """
310
+ )
311
+
312
+ async_def_example = textwrap .dedent (
313
+ """
314
+ async def some():
315
+
316
+ '''Docstring
317
+
318
+ '''
319
+ x = 1
320
+ """
321
+ )
322
+
323
+ for code in [
324
+ class_example ,
325
+ def_example ,
326
+ async_def_example ,
327
+ ]:
328
+ for opt_level in [0 , 1 , 2 ]:
329
+ with self .subTest (code = code , opt_level = opt_level ):
330
+ mod = ast .parse (code , optimize = opt_level )
331
+ if opt_level == 2 :
332
+ self .assertNotIsInstance (
333
+ mod .body [0 ].body [0 ],
334
+ (ast .Pass , ast .Expr ),
335
+ )
336
+ else :
337
+ self .assertIsInstance (mod .body [0 ].body [0 ], ast .Expr )
338
+ self .assertIsInstance (
339
+ mod .body [0 ].body [0 ].value ,
340
+ ast .Constant ,
341
+ )
342
+
343
+ compile (code , "a" , "exec" )
344
+ compile (code , "a" , "exec" , optimize = opt_level )
345
+ compile (mod , "a" , "exec" )
346
+ compile (mod , "a" , "exec" , optimize = opt_level )
347
+
223
348
def test_slice (self ):
224
349
slc = ast .parse ("x[::]" ).body [0 ].value .slice
225
350
self .assertIsNone (slc .upper )
0 commit comments