Repository: psf/black

Issue:
SyntaxWarning on regexp on first run of black
When running `black` on the following code:

```
text = re.sub(
    "([_a-zA-Z0-9-+]+)(\.[_a-zA-Z0-9-+]+)*"
    "@([a-zA-Z0-9-]+)(\.[a-zA-Z0-9-]+)*(\.[a-zA-Z]{2,4})",
    '<a href="mailto:\g<0>">\g<0></a>',
    text,
)
text = re.sub(
    "(ftp|http|https):\/\/(\w+:{0,1}\w*@)?"
    "(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?",
    '<a href="\g<0>">\g<0></a>',
    text,
)
```

I get the following warnings (written twice):

```
<unknown>:2: SyntaxWarning: invalid escape sequence '\.'
<unknown>:3: SyntaxWarning: invalid escape sequence '\.'
<unknown>:4: SyntaxWarning: invalid escape sequence '\g'
<unknown>:8: SyntaxWarning: invalid escape sequence '\/'
<unknown>:9: SyntaxWarning: invalid escape sequence '\S'
<unknown>:10: SyntaxWarning: invalid escape sequence '\g'
<unknown>:2: SyntaxWarning: invalid escape sequence '\.'
<unknown>:3: SyntaxWarning: invalid escape sequence '\.'
<unknown>:4: SyntaxWarning: invalid escape sequence '\g'
<unknown>:8: SyntaxWarning: invalid escape sequence '\/'
<unknown>:9: SyntaxWarning: invalid escape sequence '\S'
<unknown>:10: SyntaxWarning: invalid escape sequence '\g'
```

When re-running `black` on the same file, the warnings are not shown again.  I have to modify the lines (adding a space for instance) to see the warnings again.

Are these warnings normal?  (The syntax is normally correct according to the documentation of the `re` module.)
If they are normal, should they really appear twice in the output?  And why don't they appear again when running a second time `black`?


Discussion:

Resolving patch:
diff --git a/src/black/parsing.py b/src/black/parsing.py
--- a/src/black/parsing.py
+++ b/src/black/parsing.py
@@ -4,6 +4,7 @@
 
 import ast
 import sys
+import warnings
 from typing import Iterable, Iterator, List, Set, Tuple
 
 from black.mode import VERSION_TO_FEATURES, Feature, TargetVersion, supports_feature
@@ -109,13 +110,16 @@ def lib2to3_unparse(node: Node) -> str:
     return code
 
 
-def parse_single_version(
+def _parse_single_version(
     src: str, version: Tuple[int, int], *, type_comments: bool
 ) -> ast.AST:
     filename = "<unknown>"
-    return ast.parse(
-        src, filename, feature_version=version, type_comments=type_comments
-    )
+    with warnings.catch_warnings():
+        warnings.simplefilter("ignore", SyntaxWarning)
+        warnings.simplefilter("ignore", DeprecationWarning)
+        return ast.parse(
+            src, filename, feature_version=version, type_comments=type_comments
+        )
 
 
 def parse_ast(src: str) -> ast.AST:
@@ -125,7 +129,7 @@ def parse_ast(src: str) -> ast.AST:
     first_error = ""
     for version in sorted(versions, reverse=True):
         try:
-            return parse_single_version(src, version, type_comments=True)
+            return _parse_single_version(src, version, type_comments=True)
         except SyntaxError as e:
             if not first_error:
                 first_error = str(e)
@@ -133,7 +137,7 @@ def parse_ast(src: str) -> ast.AST:
     # Try to parse without type comments
     for version in sorted(versions, reverse=True):
         try:
-            return parse_single_version(src, version, type_comments=False)
+            return _parse_single_version(src, version, type_comments=False)
         except SyntaxError:
             pass
 


Test patch: