black icon indicating copy to clipboard operation
black copied to clipboard

with statement with type comment

Open 15r10nk opened this issue 2 years ago • 1 comments

Describe the bug

The following code can not be formatted

with (a,b): # type: something
    pass

when run with these arguments:

$ black example.py

The error is:

error: cannot format example.py: INTERNAL ERROR: Black produced code that is not equivalent to the source.  Please report a bug on https://github.com/psf/black/issues.  This diff might be helpful: /tmp/blk_o04ck2zv.log

Oh no! 💥 💔 💥
1 file failed to reformat.

Environment

python -m black, 23.3.1.dev10+geb32729 (compiled: no) Python (CPython) 3.11.3

Additional context

--- src
+++ dst
@@ -5,30 +5,29 @@
         Pass(
         )  # /Pass
       items=
         withitem(
           context_expr=
-            Tuple(
+            Name(
               ctx=
                 Load(
                 )  # /Load
-              elts=
-                Name(
-                  ctx=
-                    Load(
-                    )  # /Load
-                  id=
-                    'a',  # str
-                )  # /Name
-                Name(
-                  ctx=
-                    Load(
-                    )  # /Load
-                  id=
-                    'b',  # str
-                )  # /Name
-            )  # /Tuple
+              id=
+                'a',  # str
+            )  # /Name
+          optional_vars=
+            None,  # NoneType
+        )  # /withitem
+        withitem(
+          context_expr=
+            Name(
+              ctx=
+                Load(
+                )  # /Load
+              id=
+                'b',  # str
+            )  # /Name
           optional_vars=
             None,  # NoneType
         )  # /withitem
       type_comment=
         'something',  # str

15r10nk avatar May 04 '23 19:05 15r10nk

This is arguably a bug in CPython. The issue is that when using ast.parse(type_comments=True), when there is a type comment, the parentheses change how the with statement is parsed:

In [7]: ast.dump(ast.parse('''with a,b: # type: something
   ...:     pass
   ...: ''', type_comments=True))
Out[7]: "Module(body=[With(items=[withitem(context_expr=Name(id='a', ctx=Load())), withitem(context_expr=Name(id='b', ctx=Load()))], body=[Pass()], type_comment='something')], type_ignores=[])"

In [8]: ast.dump(ast.parse('''with (a,b): # type: something
   ...:     pass
   ...: ''', type_comments=True))
Out[8]: "Module(body=[With(items=[withitem(context_expr=Tuple(elts=[Name(id='a', ctx=Load()), Name(id='b', ctx=Load())], ctx=Load()))], body=[Pass()], type_comment='something')], type_ignores=[])"

In [9]: ast.dump(ast.parse('''with a,b:
   ...:     pass
   ...: ''', type_comments=True))
Out[9]: "Module(body=[With(items=[withitem(context_expr=Name(id='a', ctx=Load())), withitem(context_expr=Name(id='b', ctx=Load()))], body=[Pass()])], type_ignores=[])"

In [10]: ast.dump(ast.parse('''with (a,b):
    ...:     pass
    ...: ''', type_comments=True))
Out[10]: "Module(body=[With(items=[withitem(context_expr=Name(id='a', ctx=Load())), withitem(context_expr=Name(id='b', ctx=Load()))], body=[Pass()])], type_ignores=[])"

Worse yet, this fails to parse:

In [11]: ast.dump(ast.parse('''with (a as c,b): # type: something
    ...:     pass
    ...: ''', type_comments=True))

I'll report an upstream bug.

JelleZijlstra avatar Oct 28 '23 05:10 JelleZijlstra