Repository: psf/black

Issue:
# fmt: pass - ignore formatting for single statements
Feature request:
`# fmt: pass` would skip formatting for the single statement that immediately follows.

**Is your feature request related to a problem? Please describe.** 

Not a response to a problem but it might be helpful for the following reasons:

- Easier to use / less typing
- Can't forget to turn it back on
  - Or accidentally insert code you *do* want formatted into an unformatted block
- Encourages ignoring less code
  - One-offs are always isolated to one statement instead of potentially large chunks of code.

**Describe the solution you'd like**

```python
z = "hello " + "world"

# fmt: pass
custom_formatting = [
    0,  1,  2,
    3,  4,  5,
    6,  7,  8,
]

regular_formatting = [
   0,  1,  2,  'this will be formatted'
]
```

The `custom_formatting` list would be ignored, everything else would be formatted.

**Describe alternatives you've considered**

1. Current solution

```python
# fmt: off
ugly_code=('but I want it this way')
even_more=('dont\'t judge me')
# fmt: on
```
2. `#fmt: off` at end of line (#790)
   I believe `# fmt: pass` addresses the same concern while also being a bit more flexible.
    - a single statement could be multi-line
    - a long line would bury an inline comment
    - `# fmt: pass` is more readable & predictable as a separate line
3. Disable formatting for certain expressions only. #798
4. Deal with it

**Additional context**

Naming:

- `# fmt: pass` reflects Python's existing [pass statement](https://docs.python.org/3/reference/simple_stmts.html?highlight=pass#the-pass-statement). Hopefully this hints that you can use it to temporarily appease the formatter for one quick thing, but it's not something you want everywhere.

- Naming could be anything, e.g. "pass", "skip", "ignore"


Discussion:
I like this one..

but would like to extend it a bit more 

`foo = bar.<100 characters +>  # fmt: pass`

if i place at the end of the statement - it should work as well (not only before the statement)
I would love to see this feature merged!
> I like this one..
> 
> but would like to extend it a bit more
> 
> `foo = bar.<100 characters +> # fmt: pass`
> 
> if i place at the end of the statement - it should work as well (not only before the statement)

Expanding on @vitalik's ask. It would be great if this feature would be compatible with other inline comment options.

`def example(self):  #noqa - squelch some lint check  # fmt: pass`
The reason why I uninstalled black :(
We definitly need something like this.

I have ansible vars in my python script
which require me to write something like 
`{{ variable_name }}` which black will turn into `{{variable_name}}`
which afaik isnt valid anymore.

turning the line into
```python
# fmt: off
my_var = {{ variable_name }}
# fmt: on
```

looks very ugly in my opinion.
this however:
`my_var = {{ variable_name }} # fmt: skip`
would look quite okay.

Resolving patch:
diff --git a/src/black/__init__.py b/src/black/__init__.py
--- a/src/black/__init__.py
+++ b/src/black/__init__.py
@@ -2581,6 +2581,8 @@ def is_split_before_delimiter(leaf: Leaf, previous: Optional[Leaf] = None) -> Pr
 
 
 FMT_OFF = {"# fmt: off", "# fmt:off", "# yapf: disable"}
+FMT_SKIP = {"# fmt: skip", "# fmt:skip"}
+FMT_PASS = {*FMT_OFF, *FMT_SKIP}
 FMT_ON = {"# fmt: on", "# fmt:on", "# yapf: enable"}
 
 
@@ -5404,58 +5406,80 @@ def convert_one_fmt_off_pair(node: Node) -> bool:
     for leaf in node.leaves():
         previous_consumed = 0
         for comment in list_comments(leaf.prefix, is_endmarker=False):
-            if comment.value in FMT_OFF:
-                # We only want standalone comments. If there's no previous leaf or
-                # the previous leaf is indentation, it's a standalone comment in
-                # disguise.
-                if comment.type != STANDALONE_COMMENT:
-                    prev = preceding_leaf(leaf)
-                    if prev and prev.type not in WHITESPACE:
+            if comment.value not in FMT_PASS:
+                previous_consumed = comment.consumed
+                continue
+            # We only want standalone comments. If there's no previous leaf or
+            # the previous leaf is indentation, it's a standalone comment in
+            # disguise.
+            if comment.value in FMT_PASS and comment.type != STANDALONE_COMMENT:
+                prev = preceding_leaf(leaf)
+                if prev:
+                    if comment.value in FMT_OFF and prev.type not in WHITESPACE:
+                        continue
+                    if comment.value in FMT_SKIP and prev.type in WHITESPACE:
                         continue
 
-                ignored_nodes = list(generate_ignored_nodes(leaf))
-                if not ignored_nodes:
-                    continue
-
-                first = ignored_nodes[0]  # Can be a container node with the `leaf`.
-                parent = first.parent
-                prefix = first.prefix
-                first.prefix = prefix[comment.consumed :]
-                hidden_value = (
-                    comment.value + "\n" + "".join(str(n) for n in ignored_nodes)
-                )
-                if hidden_value.endswith("\n"):
-                    # That happens when one of the `ignored_nodes` ended with a NEWLINE
-                    # leaf (possibly followed by a DEDENT).
-                    hidden_value = hidden_value[:-1]
-                first_idx: Optional[int] = None
-                for ignored in ignored_nodes:
-                    index = ignored.remove()
-                    if first_idx is None:
-                        first_idx = index
-                assert parent is not None, "INTERNAL ERROR: fmt: on/off handling (1)"
-                assert first_idx is not None, "INTERNAL ERROR: fmt: on/off handling (2)"
-                parent.insert_child(
-                    first_idx,
-                    Leaf(
-                        STANDALONE_COMMENT,
-                        hidden_value,
-                        prefix=prefix[:previous_consumed] + "\n" * comment.newlines,
-                    ),
-                )
-                return True
+            ignored_nodes = list(generate_ignored_nodes(leaf, comment))
+            if not ignored_nodes:
+                continue
 
-            previous_consumed = comment.consumed
+            first = ignored_nodes[0]  # Can be a container node with the `leaf`.
+            parent = first.parent
+            prefix = first.prefix
+            first.prefix = prefix[comment.consumed :]
+            hidden_value = "".join(str(n) for n in ignored_nodes)
+            if comment.value in FMT_OFF:
+                hidden_value = comment.value + "\n" + hidden_value
+            if comment.value in FMT_SKIP:
+                hidden_value += "  " + comment.value
+            if hidden_value.endswith("\n"):
+                # That happens when one of the `ignored_nodes` ended with a NEWLINE
+                # leaf (possibly followed by a DEDENT).
+                hidden_value = hidden_value[:-1]
+            first_idx: Optional[int] = None
+            for ignored in ignored_nodes:
+                index = ignored.remove()
+                if first_idx is None:
+                    first_idx = index
+            assert parent is not None, "INTERNAL ERROR: fmt: on/off handling (1)"
+            assert first_idx is not None, "INTERNAL ERROR: fmt: on/off handling (2)"
+            parent.insert_child(
+                first_idx,
+                Leaf(
+                    STANDALONE_COMMENT,
+                    hidden_value,
+                    prefix=prefix[:previous_consumed] + "\n" * comment.newlines,
+                ),
+            )
+            return True
 
     return False
 
 
-def generate_ignored_nodes(leaf: Leaf) -> Iterator[LN]:
+def generate_ignored_nodes(leaf: Leaf, comment: ProtoComment) -> Iterator[LN]:
     """Starting from the container of `leaf`, generate all leaves until `# fmt: on`.
 
+    If comment is skip, returns leaf only.
     Stops at the end of the block.
     """
     container: Optional[LN] = container_of(leaf)
+    if comment.value in FMT_SKIP:
+        prev_sibling = leaf.prev_sibling
+        if comment.value in leaf.prefix and prev_sibling is not None:
+            leaf.prefix = leaf.prefix.replace(comment.value, "")
+            siblings = [prev_sibling]
+            while (
+                "\n" not in prev_sibling.prefix
+                and prev_sibling.prev_sibling is not None
+            ):
+                prev_sibling = prev_sibling.prev_sibling
+                siblings.insert(0, prev_sibling)
+            for sibling in siblings:
+                yield sibling
+        elif leaf.parent is not None:
+            yield leaf.parent
+        return
     while container is not None and container.type != token.ENDMARKER:
         if is_fmt_on(container):
             return


Test patch:
diff --git a/tests/data/fmtskip.py b/tests/data/fmtskip.py
new file mode 100644
--- /dev/null
+++ b/tests/data/fmtskip.py
@@ -0,0 +1,3 @@
+a, b = 1, 2
+c =    6  # fmt: skip
+d = 5
diff --git a/tests/data/fmtskip2.py b/tests/data/fmtskip2.py
new file mode 100644
--- /dev/null
+++ b/tests/data/fmtskip2.py
@@ -0,0 +1,17 @@
+l1 = ["This list should be broken up", "into multiple lines", "because it is way too long"]
+l2 = ["But this list shouldn't", "even though it also has", "way too many characters in it"]  # fmt: skip
+l3 = ["I have", "trailing comma", "so I should be braked",]
+
+# output
+
+l1 = [
+    "This list should be broken up",
+    "into multiple lines",
+    "because it is way too long",
+]
+l2 = ["But this list shouldn't", "even though it also has", "way too many characters in it"]  # fmt: skip
+l3 = [
+    "I have",
+    "trailing comma",
+    "so I should be braked",
+]
\ No newline at end of file
diff --git a/tests/data/fmtskip3.py b/tests/data/fmtskip3.py
new file mode 100644
--- /dev/null
+++ b/tests/data/fmtskip3.py
@@ -0,0 +1,20 @@
+a  =    3
+# fmt: off
+b,    c = 1, 2
+d =    6  # fmt: skip
+e = 5
+# fmt: on
+f = ["This is a very long line that should be formatted into a clearer line ", "by rearranging."]
+
+# output
+
+a = 3
+# fmt: off
+b,    c = 1, 2
+d =    6  # fmt: skip
+e = 5
+# fmt: on
+f = [
+    "This is a very long line that should be formatted into a clearer line ",
+    "by rearranging.",
+]
diff --git a/tests/data/fmtskip4.py b/tests/data/fmtskip4.py
new file mode 100644
--- /dev/null
+++ b/tests/data/fmtskip4.py
@@ -0,0 +1,13 @@
+a =   2
+# fmt: skip
+l = [1, 2, 3,]
+
+# output
+
+a = 2
+# fmt: skip
+l = [
+    1,
+    2,
+    3,
+]
\ No newline at end of file
diff --git a/tests/data/fmtskip5.py b/tests/data/fmtskip5.py
new file mode 100644
--- /dev/null
+++ b/tests/data/fmtskip5.py
@@ -0,0 +1,22 @@
+a, b, c = 3, 4,       5
+if (
+    a ==    3
+    and b    != 9  # fmt: skip
+    and c is not None
+):
+    print("I'm good!")
+else:
+    print("I'm bad")
+
+
+# output
+
+a, b, c = 3, 4, 5
+if (
+    a == 3
+    and b    != 9  # fmt: skip
+    and c is not None
+):
+    print("I'm good!")
+else:
+    print("I'm bad")
diff --git a/tests/test_format.py b/tests/test_format.py
--- a/tests/test_format.py
+++ b/tests/test_format.py
@@ -37,6 +37,11 @@
     "fmtonoff2",
     "fmtonoff3",
     "fmtonoff4",
+    "fmtskip",
+    "fmtskip2",
+    "fmtskip3",
+    "fmtskip4",
+    "fmtskip5",
     "fstring",
     "function",
     "function2",