diff --git a/tools/linter/adapters/_linter/bracket_pairs.py b/tools/linter/adapters/_linter/bracket_pairs.py index 23f08c9ff739..323f4da88bce 100644 --- a/tools/linter/adapters/_linter/bracket_pairs.py +++ b/tools/linter/adapters/_linter/bracket_pairs.py @@ -16,9 +16,10 @@ def bracket_pairs(tokens: Sequence[TokenInfo]) -> dict[int, int]: """Returns a dictionary mapping opening to closing brackets""" braces: dict[int, int] = {} stack: list[int] = [] + in_fstring = False for i, t in enumerate(tokens): - if t.type == token.OP: + if t.type == token.OP and not in_fstring: if t.string in BRACKETS: stack.append(i) elif inv := BRACKETS_INV.get(t.string): @@ -34,9 +35,11 @@ def bracket_pairs(tokens: Sequence[TokenInfo]) -> dict[int, int]: raise ParseError(t, f"Mismatched braces '{b}' at {begin}") elif t.type == FSTRING_START: stack.append(FSTRING_START) + in_fstring = True elif t.type == FSTRING_END: if stack.pop() != FSTRING_START: raise ParseError(t, "Mismatched FSTRING_START/FSTRING_END") + in_fstring = False if stack: raise ParseError(t, "Left open") return braces diff --git a/tools/test/set_linter_testdata/python_code.py.txt b/tools/test/set_linter_testdata/python_code.py.txt index 59d2826286a0..e805a3ca92be 100644 --- a/tools/test/set_linter_testdata/python_code.py.txt +++ b/tools/test/set_linter_testdata/python_code.py.txt @@ -30,6 +30,9 @@ class A: set = A().set +# An f string as in https://github.com/pytorch/pytorch/issues/159056 +f_string = f" {h:{w}} " + # Braced sets set1 = {1} diff --git a/tools/test/set_linter_testdata/python_code.py.txt.json b/tools/test/set_linter_testdata/python_code.py.txt.json index 772fba0149f1..22935a7904df 100644 --- a/tools/test/set_linter_testdata/python_code.py.txt.json +++ b/tools/test/set_linter_testdata/python_code.py.txt.json @@ -47,7 +47,7 @@ "char": 7, "code": "SET_LINTER", "description": null, - "line": 35, + "line": 38, "name": "Builtin `set` is deprecated", "original": null, "path": "tools/test/set_linter_testdata/python_code.py.txt", @@ -58,7 +58,7 @@ "char": 9, "code": "SET_LINTER", "description": null, - "line": 35, + "line": 38, "name": "Builtin `set` is deprecated", "original": null, "path": "tools/test/set_linter_testdata/python_code.py.txt", @@ -69,7 +69,7 @@ "char": 7, "code": "SET_LINTER", "description": null, - "line": 36, + "line": 39, "name": "Builtin `set` is deprecated", "original": null, "path": "tools/test/set_linter_testdata/python_code.py.txt", @@ -80,7 +80,7 @@ "char": 12, "code": "SET_LINTER", "description": null, - "line": 36, + "line": 39, "name": "Builtin `set` is deprecated", "original": null, "path": "tools/test/set_linter_testdata/python_code.py.txt", @@ -91,7 +91,7 @@ "char": 15, "code": "SET_LINTER", "description": null, - "line": 38, + "line": 41, "name": "Builtin `set` is deprecated", "original": null, "path": "tools/test/set_linter_testdata/python_code.py.txt", @@ -102,7 +102,7 @@ "char": 36, "code": "SET_LINTER", "description": null, - "line": 38, + "line": 41, "name": "Builtin `set` is deprecated", "original": null, "path": "tools/test/set_linter_testdata/python_code.py.txt", @@ -113,7 +113,7 @@ "char": 17, "code": "SET_LINTER", "description": null, - "line": 41, + "line": 44, "name": "Builtin `set` is deprecated", "original": null, "path": "tools/test/set_linter_testdata/python_code.py.txt", @@ -124,7 +124,7 @@ "char": 22, "code": "SET_LINTER", "description": null, - "line": 41, + "line": 44, "name": "Builtin `set` is deprecated", "original": null, "path": "tools/test/set_linter_testdata/python_code.py.txt", @@ -135,7 +135,7 @@ "char": 30, "code": "SET_LINTER", "description": null, - "line": 41, + "line": 44, "name": "Builtin `set` is deprecated", "original": null, "path": "tools/test/set_linter_testdata/python_code.py.txt", @@ -146,7 +146,7 @@ "char": 50, "code": "SET_LINTER", "description": null, - "line": 41, + "line": 44, "name": "Builtin `set` is deprecated", "original": null, "path": "tools/test/set_linter_testdata/python_code.py.txt", @@ -157,7 +157,7 @@ "char": 10, "code": "SET_LINTER", "description": null, - "line": 44, + "line": 47, "name": "Builtin `set` is deprecated", "original": null, "path": "tools/test/set_linter_testdata/python_code.py.txt", @@ -168,7 +168,7 @@ "char": 51, "code": "SET_LINTER", "description": null, - "line": 44, + "line": 47, "name": "Builtin `set` is deprecated", "original": null, "path": "tools/test/set_linter_testdata/python_code.py.txt", @@ -179,7 +179,7 @@ "char": 75, "code": "SET_LINTER", "description": null, - "line": 44, + "line": 47, "name": "Builtin `set` is deprecated", "original": null, "path": "tools/test/set_linter_testdata/python_code.py.txt", @@ -190,7 +190,7 @@ "char": 77, "code": "SET_LINTER", "description": null, - "line": 44, + "line": 47, "name": "Builtin `set` is deprecated", "original": null, "path": "tools/test/set_linter_testdata/python_code.py.txt", @@ -203,9 +203,9 @@ "description": null, "line": null, "name": "Suggested fixes for set_linter", - "original": "# Basic tests\nimport tempfile\n\nprint(f\"{tempfile.gettempdir()}/memory_snapshot.pickle\")\n\nignored = set() # noqa: set_linter\na = set()\nb = \"set()\"\nc = set\nd = c.set\nf = (\n set(\n )\n)\nignored = (\n set( # noqa: set_linter\n )\n)\n\n# Non-sets\n\nd = {}\nlong_string = \"\"\" set()\nset() set x.set set()\n\\\"\"\"\"\n\nclass A:\n def set(self, x):\n self.x = x\n\nset = A().set\n\n# Braced sets\n\nset1 = {1}\nset2 = {1, 2}\n\niterator_set = {i for i in range(10)}\n\n# A dict with two sets.\ndict_set = {\"a\": {2, 3}, \"b\": {i for i in range(3)}}\n\n# A set containing an object constructed with a dict and a set\nsos_set = {Something({i: i + 1 for i in range(3)}, {i + 1 for i in range(3)})}\n", + "original": "# Basic tests\nimport tempfile\n\nprint(f\"{tempfile.gettempdir()}/memory_snapshot.pickle\")\n\nignored = set() # noqa: set_linter\na = set()\nb = \"set()\"\nc = set\nd = c.set\nf = (\n set(\n )\n)\nignored = (\n set( # noqa: set_linter\n )\n)\n\n# Non-sets\n\nd = {}\nlong_string = \"\"\" set()\nset() set x.set set()\n\\\"\"\"\"\n\nclass A:\n def set(self, x):\n self.x = x\n\nset = A().set\n\n# An f string as in https://github.com/pytorch/pytorch/issues/159056\nf_string = f\" {h:{w}} \"\n\n# Braced sets\n\nset1 = {1}\nset2 = {1, 2}\n\niterator_set = {i for i in range(10)}\n\n# A dict with two sets.\ndict_set = {\"a\": {2, 3}, \"b\": {i for i in range(3)}}\n\n# A set containing an object constructed with a dict and a set\nsos_set = {Something({i: i + 1 for i in range(3)}, {i + 1 for i in range(3)})}\n", "path": "tools/test/set_linter_testdata/python_code.py.txt", - "replacement": "# Basic tests\nimport tempfile\nfrom torch.utils._ordered_set import OrderedSet\n\n\nprint(f\"{tempfile.gettempdir()}/memory_snapshot.pickle\")\n\nignored = set() # noqa: set_linter\na = OrderedSet()\nb = \"set()\"\nc = OrderedSet\nd = c.set\nf = (\n OrderedSet(\n )\n)\nignored = (\n set( # noqa: set_linter\n )\n)\n\n# Non-sets\n\nd = {}\nlong_string = \"\"\" set()\nset() set x.set set()\n\\\"\"\"\"\n\nclass A:\n def set(self, x):\n self.x = x\n\nset = A().set\n\n# Braced sets\n\nset1 = OrderedSet([1])\nset2 = OrderedSet([1, 2])\n\niterator_set = OrderedSet([i for i in range(10)])\n\n# A dict with two sets.\ndict_set = {\"a\": OrderedSet([2, 3]), \"b\": OrderedSet([i for i in range(3)])}\n\n# A set containing an object constructed with a dict and a set\nsos_set = OrderedSet([Something({i: i + 1 for i in range(3)}, OrderedSet([i + 1 for i in range(3)]))])\n", + "replacement": "# Basic tests\nimport tempfile\nfrom torch.utils._ordered_set import OrderedSet\n\n\nprint(f\"{tempfile.gettempdir()}/memory_snapshot.pickle\")\n\nignored = set() # noqa: set_linter\na = OrderedSet()\nb = \"set()\"\nc = OrderedSet\nd = c.set\nf = (\n OrderedSet(\n )\n)\nignored = (\n set( # noqa: set_linter\n )\n)\n\n# Non-sets\n\nd = {}\nlong_string = \"\"\" set()\nset() set x.set set()\n\\\"\"\"\"\n\nclass A:\n def set(self, x):\n self.x = x\n\nset = A().set\n\n# An f string as in https://github.com/pytorch/pytorch/issues/159056\nf_string = f\" {h:{w}} \"\n\n# Braced sets\n\nset1 = OrderedSet([1])\nset2 = OrderedSet([1, 2])\n\niterator_set = OrderedSet([i for i in range(10)])\n\n# A dict with two sets.\ndict_set = {\"a\": OrderedSet([2, 3]), \"b\": OrderedSet([i for i in range(3)])}\n\n# A set containing an object constructed with a dict and a set\nsos_set = OrderedSet([Something({i: i + 1 for i in range(3)}, OrderedSet([i + 1 for i in range(3)]))])\n", "severity": "error" } ] diff --git a/tools/test/set_linter_testdata/python_code.py.txt.lintrunner b/tools/test/set_linter_testdata/python_code.py.txt.lintrunner index 901cd664f96d..4926368e9ab1 100644 --- a/tools/test/set_linter_testdata/python_code.py.txt.lintrunner +++ b/tools/test/set_linter_testdata/python_code.py.txt.lintrunner @@ -30,106 +30,106 @@ tools/test/set_linter_testdata/python_code.py.txt:12:4: Builtin `set` is depreca 13 | ) 14 | ) -tools/test/set_linter_testdata/python_code.py.txt:35:8: Builtin `set` is deprecated - 33 | # Braced sets - 34 | - 35 | set1 = {1} - ^ - 36 | set2 = {1, 2} +tools/test/set_linter_testdata/python_code.py.txt:38:8: Builtin `set` is deprecated + 36 | # Braced sets 37 | + 38 | set1 = {1} + ^ + 39 | set2 = {1, 2} + 40 | -tools/test/set_linter_testdata/python_code.py.txt:35:10: Builtin `set` is deprecated - 33 | # Braced sets - 34 | - 35 | set1 = {1} +tools/test/set_linter_testdata/python_code.py.txt:38:10: Builtin `set` is deprecated + 36 | # Braced sets + 37 | + 38 | set1 = {1} ^ - 36 | set2 = {1, 2} - 37 | + 39 | set2 = {1, 2} + 40 | -tools/test/set_linter_testdata/python_code.py.txt:36:8: Builtin `set` is deprecated - 34 | - 35 | set1 = {1} - 36 | set2 = {1, 2} +tools/test/set_linter_testdata/python_code.py.txt:39:8: Builtin `set` is deprecated + 37 | + 38 | set1 = {1} + 39 | set2 = {1, 2} ^ - 37 | - 38 | iterator_set = {i for i in range(10)} + 40 | + 41 | iterator_set = {i for i in range(10)} -tools/test/set_linter_testdata/python_code.py.txt:36:13: Builtin `set` is deprecated - 34 | - 35 | set1 = {1} - 36 | set2 = {1, 2} +tools/test/set_linter_testdata/python_code.py.txt:39:13: Builtin `set` is deprecated + 37 | + 38 | set1 = {1} + 39 | set2 = {1, 2} ^ - 37 | - 38 | iterator_set = {i for i in range(10)} + 40 | + 41 | iterator_set = {i for i in range(10)} -tools/test/set_linter_testdata/python_code.py.txt:38:16: Builtin `set` is deprecated - 36 | set2 = {1, 2} - 37 | - 38 | iterator_set = {i for i in range(10)} +tools/test/set_linter_testdata/python_code.py.txt:41:16: Builtin `set` is deprecated + 39 | set2 = {1, 2} + 40 | + 41 | iterator_set = {i for i in range(10)} ^ - 39 | - 40 | # A dict with two sets. + 42 | + 43 | # A dict with two sets. -tools/test/set_linter_testdata/python_code.py.txt:38:37: Builtin `set` is deprecated - 36 | set2 = {1, 2} - 37 | - 38 | iterator_set = {i for i in range(10)} +tools/test/set_linter_testdata/python_code.py.txt:41:37: Builtin `set` is deprecated + 39 | set2 = {1, 2} + 40 | + 41 | iterator_set = {i for i in range(10)} ^ - 39 | - 40 | # A dict with two sets. + 42 | + 43 | # A dict with two sets. -tools/test/set_linter_testdata/python_code.py.txt:41:18: Builtin `set` is deprecated - 39 | - 40 | # A dict with two sets. - 41 | dict_set = {"a": {2, 3}, "b": {i for i in range(3)}} +tools/test/set_linter_testdata/python_code.py.txt:44:18: Builtin `set` is deprecated + 42 | + 43 | # A dict with two sets. + 44 | dict_set = {"a": {2, 3}, "b": {i for i in range(3)}} ^ - 42 | - 43 | # A set containing an object constructed with a dict and a set + 45 | + 46 | # A set containing an object constructed with a dict and a set -tools/test/set_linter_testdata/python_code.py.txt:41:23: Builtin `set` is deprecated - 39 | - 40 | # A dict with two sets. - 41 | dict_set = {"a": {2, 3}, "b": {i for i in range(3)}} +tools/test/set_linter_testdata/python_code.py.txt:44:23: Builtin `set` is deprecated + 42 | + 43 | # A dict with two sets. + 44 | dict_set = {"a": {2, 3}, "b": {i for i in range(3)}} ^ - 42 | - 43 | # A set containing an object constructed with a dict and a set + 45 | + 46 | # A set containing an object constructed with a dict and a set -tools/test/set_linter_testdata/python_code.py.txt:41:31: Builtin `set` is deprecated - 39 | - 40 | # A dict with two sets. - 41 | dict_set = {"a": {2, 3}, "b": {i for i in range(3)}} +tools/test/set_linter_testdata/python_code.py.txt:44:31: Builtin `set` is deprecated + 42 | + 43 | # A dict with two sets. + 44 | dict_set = {"a": {2, 3}, "b": {i for i in range(3)}} ^ - 42 | - 43 | # A set containing an object constructed with a dict and a set + 45 | + 46 | # A set containing an object constructed with a dict and a set -tools/test/set_linter_testdata/python_code.py.txt:41:51: Builtin `set` is deprecated - 39 | - 40 | # A dict with two sets. - 41 | dict_set = {"a": {2, 3}, "b": {i for i in range(3)}} +tools/test/set_linter_testdata/python_code.py.txt:44:51: Builtin `set` is deprecated + 42 | + 43 | # A dict with two sets. + 44 | dict_set = {"a": {2, 3}, "b": {i for i in range(3)}} ^ - 42 | - 43 | # A set containing an object constructed with a dict and a set + 45 | + 46 | # A set containing an object constructed with a dict and a set -tools/test/set_linter_testdata/python_code.py.txt:44:11: Builtin `set` is deprecated - 42 | - 43 | # A set containing an object constructed with a dict and a set - 44 | sos_set = {Something({i: i + 1 for i in range(3)}, {i + 1 for i in range(3)})} +tools/test/set_linter_testdata/python_code.py.txt:47:11: Builtin `set` is deprecated + 45 | + 46 | # A set containing an object constructed with a dict and a set + 47 | sos_set = {Something({i: i + 1 for i in range(3)}, {i + 1 for i in range(3)})} ^ -tools/test/set_linter_testdata/python_code.py.txt:44:52: Builtin `set` is deprecated - 42 | - 43 | # A set containing an object constructed with a dict and a set - 44 | sos_set = {Something({i: i + 1 for i in range(3)}, {i + 1 for i in range(3)})} +tools/test/set_linter_testdata/python_code.py.txt:47:52: Builtin `set` is deprecated + 45 | + 46 | # A set containing an object constructed with a dict and a set + 47 | sos_set = {Something({i: i + 1 for i in range(3)}, {i + 1 for i in range(3)})} ^ -tools/test/set_linter_testdata/python_code.py.txt:44:76: Builtin `set` is deprecated - 42 | - 43 | # A set containing an object constructed with a dict and a set - 44 | sos_set = {Something({i: i + 1 for i in range(3)}, {i + 1 for i in range(3)})} +tools/test/set_linter_testdata/python_code.py.txt:47:76: Builtin `set` is deprecated + 45 | + 46 | # A set containing an object constructed with a dict and a set + 47 | sos_set = {Something({i: i + 1 for i in range(3)}, {i + 1 for i in range(3)})} ^ -tools/test/set_linter_testdata/python_code.py.txt:44:78: Builtin `set` is deprecated - 42 | - 43 | # A set containing an object constructed with a dict and a set - 44 | sos_set = {Something({i: i + 1 for i in range(3)}, {i + 1 for i in range(3)})} +tools/test/set_linter_testdata/python_code.py.txt:47:78: Builtin `set` is deprecated + 45 | + 46 | # A set containing an object constructed with a dict and a set + 47 | sos_set = {Something({i: i + 1 for i in range(3)}, {i + 1 for i in range(3)})} ^ diff --git a/tools/test/set_linter_testdata/python_code.py.txt.python b/tools/test/set_linter_testdata/python_code.py.txt.python index 3dbabd3e7845..52aaf12f2631 100644 --- a/tools/test/set_linter_testdata/python_code.py.txt.python +++ b/tools/test/set_linter_testdata/python_code.py.txt.python @@ -32,6 +32,9 @@ class A: set = A().set +# An f string as in https://github.com/pytorch/pytorch/issues/159056 +f_string = f" {h:{w}} " + # Braced sets set1 = OrderedSet([1]) diff --git a/tools/test/test_set_linter.py b/tools/test/test_set_linter.py index 9e879c8c6112..003096c3c408 100644 --- a/tools/test/test_set_linter.py +++ b/tools/test/test_set_linter.py @@ -77,6 +77,7 @@ class TestSetLinter(LinterTestCase): ("{i for i in range(2, 3)}", 1), ("{1, 2}", 1), ("{One({'a': 1}), Two([{}, {2}, {1, 2}])}", 3), + ('f" {h:{w}} "', 0), ) for s, expected in TESTS: pf = SetLinter.make_file(s)